﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Pixysoft.Framework.Reflection.Core;
using Pixysoft.TestDrivens;
using Pixysoft.Tools;
using System.Collections;

namespace Pixysoft.Framework.Reflection.testdriven
{
    [TestDriven]
    class Class_dynamic
    {
        public void test001()
        {
            // 100000
            //reflection
            //    Time Elapsed:		631ms
            //    CPU time:		515,625,000ns
            //    Gen 0: 			0
            //    Gen 1: 			0
            //    Gen 2: 			0

            //dynamic
            //    Time Elapsed:		253ms
            //    CPU time:		250,000,000ns
            //    Gen 0: 			132
            //    Gen 1: 			0
            //    Gen 2: 			0


            SomeClass c = new SomeClass();

            CodeTimer.Initialize();

            CodeTimer.Time("reflection", 100000, delegate()
            {
                FieldInfo field = c.GetType().GetField("sname");
                field.SetValue(c, "test");
                field.GetValue(c);
            });


            CodeTimer.Time("dynamic", 100000, delegate()
            {
                IDynamicType dtype = ReflectionManager.CreateDynamicType(c.GetType());
                IDynamicFieldInfo dfield = dtype.GetField("sname");
                dfield.SetValue(c, "test");
                dfield.GetValue(c);
            });
        }

        //set field
        public void test003()
        {

            //begin reflection.
            //end reflection
            //00:00:02.8281250

            //begin dynamic.
            //end dynamic
            //00:00:00.0156250

            SomeClass c = new SomeClass();

            FieldInfo field = c.GetType().GetField("sname");

            StartTest("begin reflection.");

            for (int i = 0; i < 1000000; i++)
            {
                field.SetValue(c, "test");
            }

            EndTest("end reflection");

            IDynamicFieldInfo dfield = new DynamicType(c.GetType()).GetField("sname");

            StartTest("begin dynamic.");

            for (int i = 0; i < 1000000; i++)
            {
                dfield.SetValue(c, "test");
            }

            EndTest("end dynamic");
        }

        //get field
        public void test004()
        {
            SomeClass c = new SomeClass();

            FieldInfo field = c.GetType().GetField("sname");

            StartTest("begin reflection.");

            field.SetValue(c, "test");

            for (int i = 0; i < 1000000; i++)
            {
                field.GetValue(c);
            }

            EndTest("end reflection");




            IDynamicFieldInfo dfield = new DynamicType(c.GetType()).GetField("sname");

            dfield.SetValue(c, "test");

            StartTest("begin dynamic.");

            for (int i = 0; i < 1000000; i++)
            {
                dfield.GetValue(c);
            }

            EndTest("end dynamic");
        }

        //set property
        public void test005()
        {
            SomeClass c = new SomeClass();

            PropertyInfo property = c.GetType().GetProperty("Name");

            StartTest("begin reflection.");

            for (int i = 0; i < 100000; i++)
            {
                property.SetValue(c, i, null);
            }

            EndTest("end reflection");

            IDynamicPropertyInfo dproperty = new DynamicType(c.GetType()).GetProperty("Name");

            StartTest("begin dynamic.");

            for (int i = 0; i < 100000; i++)
            {
                dproperty.SetValue(c, i, null);
            }

            EndTest("end dynamic");
        }

        //get property
        public void test006()
        {
            SomeClass c = new SomeClass();

            PropertyInfo property = c.GetType().GetProperty("Sname");

            StartTest("begin reflection.");

            for (int i = 0; i < 100000; i++)
            {
                property.GetValue(c, null);
            }

            EndTest("end reflection");




            IDynamicPropertyInfo dproperty = new DynamicType(c.GetType()).GetProperty("Sname");

            StartTest("begin dynamic.");

            for (int i = 0; i < 100000; i++)
            {
                dproperty.GetValue(c, null);
            }

            EndTest("end dynamic");
        }

        //constructor
        public void test008()
        {
            //100000 times

            //------ Test started: Assembly: Pixysoft.Framework.Reflection.dll ------

            //reflection
            //    Time Elapsed:		751ms
            //    CPU time:		718,750,000ns
            //    Gen 0: 			54
            //    Gen 1: 			0
            //    Gen 2: 			0

            //dynamic outside
            //    Time Elapsed:		7ms
            //    CPU time:		15,625,000ns
            //    Gen 0: 			6
            //    Gen 1: 			0
            //    Gen 2: 			0

            //dynamic inside
            //    Time Elapsed:		234ms
            //    CPU time:		218,750,000ns
            //    Gen 0: 			159
            //    Gen 1: 			0
            //    Gen 2: 			0

            //reflection array
            //    Time Elapsed:		107ms
            //    CPU time:		109,375,000ns
            //    Gen 0: 			10
            //    Gen 1: 			1
            //    Gen 2: 			0

            //dynamic array
            //    Time Elapsed:		265ms
            //    CPU time:		265,625,000ns
            //    Gen 0: 			171
            //    Gen 1: 			0
            //    Gen 2: 			0

            //reflection list
            //    Time Elapsed:		310ms
            //    CPU time:		296,875,000ns
            //    Gen 0: 			4
            //    Gen 1: 			1
            //    Gen 2: 			0

            //dynamic list
            //    Time Elapsed:		311ms
            //    CPU time:		312,500,000ns
            //    Gen 0: 			275
            //    Gen 1: 			0
            //    Gen 2: 			0


            //1 passed, 0 failed, 0 skipped, took 2.28 seconds (Ad hoc).




            Type type = typeof(SomeClass);

            CodeTimer.Initialize();

            CodeTimer.Time("reflection", 100000, delegate()
            {
                object result = Activator.CreateInstance(type, "hello");
            });


            IDynamicConstructorInfo dConstructorInfo = new DynamicType(type).GetConstructor(new Type[] { typeof(string) });

            CodeTimer.Time("dynamic outside", 100000, delegate()
            {
                object result = dConstructorInfo.Invoke(new object[] { "hello" });
            });

            CodeTimer.Time("dynamic inside", 100000, delegate()
            {
                object result = new DynamicType(type).GetConstructor(new Type[] { typeof(string) }).Invoke(new object[] { "hello" });
            });



            Type targetTYpe = typeof(SomeClass[]);

            CodeTimer.Time("reflection array", 100000, delegate()
            {
                object result = Array.CreateInstance(targetTYpe, 10);
            });


            CodeTimer.Time("dynamic array", 100000, delegate()
            {
                object result = ReflectionManager.CreateDynamicType(targetTYpe).GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { 10 });
            });

            targetTYpe = typeof(List<SomeClass>);

            CodeTimer.Time("reflection list", 100000, delegate()
            {
                IList listObjectValue = Activator.CreateInstance(targetTYpe) as IList;
            });


            CodeTimer.Time("dynamic list", 100000, delegate()
            {
                IList listObjectValue = ReflectionManager.CreateDynamicType(targetTYpe).GetDefaultConstructor().Invoke() as IList;
            });
        }

        //hashcode
        public void test009()
        {
            for (int i = 0; i < 10; i++)
                Console.WriteLine(new SomeClass().GetHashCode());
        }

        //method
        public void test010()
        {
            SomeClass s = new SomeClass();

            IDynamicMethodInfo method1 = ReflectionManager.CreateDynamicType(typeof(SomeClass)).GetMethod("Hello",
                new Type[] { });
            method1.Invoke(s, null);


            IDynamicMethodInfo method = ReflectionManager.CreateDynamicType(typeof(SomeClass)).GetMethod("Hello",
                new Type[] { typeof(string), typeof(int) });
            method.Invoke(s, new object[] { "123", 1 });
        }

        [TestCase]
        public static void test011()
        {
            SomeClass c = new SomeClass();

            IDynamicFieldInfo dfield = new DynamicType(c.GetType()).GetField("sname");

            dfield.SetValue(c, "test");

            Assert.SaveOrVerify("dynamic set field", dfield.GetValue(c));


            IDynamicPropertyInfo dproperty = new DynamicType(c.GetType()).GetProperty("Name");

            dproperty.SetValue(c, 111, null);

            Assert.SaveOrVerify("dynamic set property", dproperty.GetValue(c, null));
        }


        private static DateTime lastTestStartTime;

        // StartTest
        private static void StartTest(string message)
        {
            lastTestStartTime = DateTime.Now;
            Console.WriteLine(message);
        }

        // EndTest
        private static void EndTest(string message)
        {
            Console.WriteLine(message);
            Console.WriteLine(DateTime.Now - lastTestStartTime);
            Console.WriteLine("");
        }


        private object DynamicMethod(object obj, object[] objs)
        {
            ((SomeClass)obj).Hello();
            return null;
        }
    }

    class SomeClass : ISomeClass
    {
        public int name;
        public string sname;

        public SomeClass()
        {
        }
        public SomeClass(string name)
        {
            this.sname = name;

        }

        public void Hello()
        {
            Console.WriteLine("hello");
        }
        public void Hello(string name, int a)
        {
            Console.WriteLine("hello2");
        }
        public int Name
        {
            get { return name; }
            set { name = value; }
        }
        public string Sname
        {
            get { return sname; }
            set { sname = value; }
        }
        public string this[int index, string name, int a, int b, string c, double d]
        {
            get
            {
                return index.ToString() + name;
            }
            set
            {
            }
        }
    }

    interface ISomeClass
    {
        void Hello();
        void Hello(string name, int a);
    }
}
